/*--------------------------------------------------------------------------
 *  Copyright 2011 Taro L. Saito
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *--------------------------------------------------------------------------*/
//--------------------------------------
// XerialJ
//
// SilkTreeParser.java
// Since: 2011/06/08 23:51:04
//
// $URL$
// $Author$
//--------------------------------------
package org.xerial.silk.parser;

import java.io.IOException;
import java.io.InputStream;

import org.xerial.silk.model.SilkElement;
import org.xerial.silk.model.SilkNode;
import org.xerial.util.ArrayDeque;
import org.xerial.util.tree.TreeEventHandler;

/**
 * Parsing Silk and generates a tree event stream.
 * 
 * @author leo
 * 
 */
public class SilkTreeParser
{
    private SilkParser parser;

    private static class ParsingContext
    {
        public final int      indentLevel;
        public final SilkNode node;
        public boolean        needToClose = true;

        public ParsingContext(int indentLevel, SilkNode node, boolean needToClose) {
            this.indentLevel = indentLevel;
            this.node = node;
            this.needToClose = needToClose;
        }
    }

    private ArrayDeque<ParsingContext> contextStack = new ArrayDeque<ParsingContext>();
    private TreeEventHandler           handler;

    public SilkTreeParser(InputStream in) {
        this.parser = new SilkParser(in);
    }

    public void close() throws IOException {
        parser.close();
    }

    public void parse(TreeEventHandler handler) throws Exception {

        this.handler = handler;
        handler.init();

        parser.parse(new SilkElementHandler() {
            @Override
            public void handle(SilkElement element) throws Exception {
                switch (element.getType()) {
                case Node: {
                    SilkNode node = element.cast();
                    parseNode(node);
                    break;
                }
                case DataLine:
                    break;
                case Function:
                    break;
                // Ignore elements that do not produce tree events
                case BlankLine:
                case Comment:
                case Preamble:
                    break;
                }

            }
        });

        handler.finish();
    }

    void parseNode(SilkNode node) throws Exception {
        switch (node.nodeType) {
        case SINGLE:
            while (!contextStack.isEmpty() && contextStack.peekLast().indentLevel >= node.indent) {
                ParsingContext c = contextStack.pollLast();
                if (c.needToClose)
                    handler.leaveNode(c.node.name.toString());
            }
            handler.visitNode(node.getName().toString(), node.hasValue() ? node.value.toString() : null);
            if (node.hasChildren()) {
                for (SilkNode attr : node.childNodeList) {
                    handler.visitNode(attr.name.toString(), attr.hasValue() ? attr.value.toString() : null);
                    handler.leaveNode(attr.name.toString());
                }
            }
            contextStack.addLast(new ParsingContext(node.indent, node, true));

            break;
        case TAB:

            break;
        case FUNCTION:
            break;
        case HEREDOC:
            break;
        case BLOCK:
            break;
        case SEQUENCE:
            break;
        }
    }

}
